package com.dyh.quickdemozwei.controller.http;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class HttpUtils {

	private static String renderUrl(String url, Map<String, List<String>> params) {
		StringBuilder sb = new StringBuilder();
		sb.append(url);
		if(!url.contains("?")) {
			sb.append("?");
		}
		Boolean isFirstParam = true;
		for(Entry<String, List<String>> entry : params.entrySet()) {
			List<String> vals = entry.getValue();
			if(CollectionUtils.isEmpty(vals)) continue;
			for(String val : vals) {
				if (isFirstParam) {
					isFirstParam = false;
					sb.append(entry.getKey())
						.append("=")
						.append(encodeParam(val));
				} else {
					sb.append("&")
						.append(entry.getKey())
						.append("=")
						.append(encodeParam(val));
				}

			}
		}
		return sb.toString();
	}
	
	private static Map<Character, String> encoderMap = new HashMap<Character, String>();
	
	static {
		encoderMap.put('+', "%2B");
		encoderMap.put(' ', "%20");
		encoderMap.put('/', "%2F");
		encoderMap.put('?', "%3F");
		encoderMap.put('%', "%25");
		encoderMap.put('#', "%23");
		encoderMap.put('&', "%26");
		encoderMap.put('=', "%3D");
	}
	
	private static String encodeParam(String param) {
		if(param == null) return "";
		StringBuilder sb = new StringBuilder();
		for(char c : param.toCharArray()) {
			String encodeString = encoderMap.get(c);
			if(encodeString == null) {
				sb.append(c);
			} else {
				sb.append(encodeString);
			}
		}
		return sb.toString();
	}
	
	public static String request(String url, HttpMethod method, HttpContext context, HttpBody body) {
		try {
			if(context == null) {
				context = new HttpContext();
			}
			Map<String, List<String>> params = context.getParams();
			if(params != null) {
				url = renderUrl(url, params);
			}
			HttpURLConnection conn = (HttpURLConnection)getConnection(url);
			conn.setRequestMethod(method.toString());
			conn.setRequestProperty("content-type", context.getContentType());
			Map<String, String> headers = context.getHeaders();
			if(headers != null) {
				for(Entry<String, String> entry : headers.entrySet()) {
					conn.setRequestProperty(entry.getKey(), entry.getValue());
				}
			}
			conn.setDoInput(true);
			if(body != null) {
				conn.setDoOutput(true);
				OutputStream out = conn.getOutputStream();
				try {
					IOUtils.copy(body.toInputStream(context), out);
					out.flush();
				} finally {
					IOUtils.closeQuietly(out);
				}
			}
			InputStream in = conn.getInputStream();
			try {
				return IOUtils.toString(in, context.getReadCharset());
			} finally {
				IOUtils.closeQuietly(in);
			}
		} catch(IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static String get(String url) {
		return request(url, HttpMethod.GET, null, null);
	}
	
	public static String get(String url, HttpContext context) {
		return request(url, HttpMethod.GET, context, null);
	}
	
	public static String post(String url) {
		return request(url, HttpMethod.POST, null, null);
	}
	
	public static String post(String url, HttpContext context) {
		return request(url, HttpMethod.POST, context, null);
	}
	
	public static String post(String url, HttpContext context, HttpBody body) {
		return request(url, HttpMethod.POST, context, body);
	}
	
	private static URLConnection getConnection(String url) throws IOException {
		URLConnection connection = new URL(url).openConnection();
		if (connection instanceof HttpsURLConnection) {
			HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
			httpsConnection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
			httpsConnection.setHostnameVerifier(HOSTNAME_VERIFIER);
		}
		return connection;
	}

	private static final TrustManager[] TRUST_MANAGERS = new TrustManager[] { new X509TrustManager() {
		@Override
		public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
		}

		@Override
		public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}
	} };

	private static SSLContext SSL_CONTEXT = null;
	private static SSLSocketFactory SSL_SOCKET_FACTORY = null;

	static {
		try {
			SSL_CONTEXT = SSLContext.getInstance("SSL");
			SSL_CONTEXT.init(null, TRUST_MANAGERS, new java.security.SecureRandom());
			SSL_SOCKET_FACTORY = SSL_CONTEXT.getSocketFactory();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private static HostnameVerifier HOSTNAME_VERIFIER = new HostnameVerifier() {
		@Override
		public boolean verify(String hostname, SSLSession session) {
			return true;
		}
	};
	
	public static void main(String[] args) {
		String url = "https://www.baidu.com";
		HttpContext context = new HttpContext();
		context.addParams("wd", "123&");
		context.addHeader(UserAgent.NAME, UserAgent.CHROM_WIN);
		System.out.println(get(url, context));
	}
}